Skip to content

Guard MarshalByRefObject, [Serializable], and InitializeLifetimeService behind #if NETFRAMEWORK#8174

Merged
Evangelink merged 7 commits into
mainfrom
dev/amauryleve/guard-netfx-remoting-artifacts
May 15, 2026
Merged

Guard MarshalByRefObject, [Serializable], and InitializeLifetimeService behind #if NETFRAMEWORK#8174
Evangelink merged 7 commits into
mainfrom
dev/amauryleve/guard-netfx-remoting-artifacts

Conversation

@Evangelink
Copy link
Copy Markdown
Member

Summary

Audit and clean up MarshalByRefObject and [Serializable] usage across src/ to ensure these .NET Framework remoting artifacts are properly scoped to net462 only.

Changes

MarshalByRefObject inheritance (10 classes)

Made all MarshalByRefObject base class inheritance conditional on #if NETFRAMEWORK:

Classes with only MarshalByRefObject as base (6):

  • AssemblyEnumerator, ReflectHelper, RecursiveDirectoryPath, UnitTestRunner, TypeCache, TestAssemblySettingsProvider

Classes implementing MarshalByRefObject + an interface (4):

  • RemotingMessageLogger, NopTraceLogger, EqtTraceLogger, MTPTraceLogger

InitializeLifetimeService overrides (6 methods)

Wrapped all InitializeLifetimeService() overrides (including [SecurityCritical] and the previous [Obsolete] attributes) entirely in #if NETFRAMEWORK. On net462, the override returns null for infinite lifetime. On modern .NET, the override doesn't exist since the base class is no longer MarshalByRefObject.

Also conditionally included using System.Security; to avoid IDE0005 warnings.

[Serializable] attribute (11 non-exception types)

Guarded [Serializable] with #if NETFRAMEWORK on data types that only needed it for BinaryFormatter marshaling across AppDomain boundaries:

  • RecursiveDirectoryPath, UnitTestElement, TestMethod, TestAssemblySettings, StackTraceInformation, MSTestSettings, AssemblyEnumerationResult, TestRunDirectories, DeploymentItem, DeploymentItemOriginType, TestResult

Exception types (AssertFailedException, UnitTestAssertException, etc.) intentionally retain [Serializable] unconditionally — this is a standard .NET convention for exceptions.

Already correctly guarded (no changes needed)

These were already behind #if NETFRAMEWORK:

  • AssemblyLoadWorker, StaticStateHelper (in AppDomainUtilities.cs), AssemblyResolver (conditional base class)
  • All AppDomain.CreateDomain/Unload calls in AppDomainUtilities.cs, AppDomainWrapper.cs, IAppDomain.cs, TestSourceHost.cs

Result

On modern .NET (net8.0/net9.0), these classes are now plain types with no remoting or BinaryFormatter baggage. On net462, the full AppDomain marshaling support is preserved.

Validation

  • dotnet build net9.0 — 0 warnings, 0 errors
  • dotnet build net462 — 0 warnings, 0 errors
  • dotnet build MSTest.TestAdapter net9.0 — 0 warnings, 0 errors
  • dotnet build TestFramework net9.0 — 0 warnings, 0 errors

…ce behind #if NETFRAMEWORK

- Make all MarshalByRefObject inheritance conditional on NETFRAMEWORK across 10 classes
- Wrap InitializeLifetimeService overrides and [SecurityCritical] in #if NETFRAMEWORK
- Guard [Serializable] with #if NETFRAMEWORK on 11 non-exception data types
- Conditionally include 'using System.Security' only for NETFRAMEWORK
- Exception types retain [Serializable] unconditionally (standard .NET convention)

On modern .NET (net8.0/net9.0), these classes are now plain types with no
remoting or BinaryFormatter baggage. On net462, the full AppDomain marshaling
support is preserved.
Copilot AI review requested due to automatic review settings May 13, 2026 10:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR scopes .NET Framework remoting/serialization artifacts (MarshalByRefObject, [Serializable], and InitializeLifetimeService) to #if NETFRAMEWORK, keeping AppDomain marshaling behavior on net462 while removing remoting-related baggage from modern .NET builds.

Changes:

  • Guarded MarshalByRefObject inheritance and InitializeLifetimeService() overrides behind #if NETFRAMEWORK.
  • Guarded [Serializable] on non-exception transport/data types behind #if NETFRAMEWORK.
  • Conditionally included using System.Security; only where [SecurityCritical] is compiled to avoid unused-using warnings.
Show a summary per file
File Description
src/TestFramework/TestFramework/Attributes/TestMethod/TestResult.cs Makes TestResult [Serializable] only on .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/RecursiveDirectoryPath.cs Guards [Serializable], MarshalByRefObject, InitializeLifetimeService, and System.Security usage to .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestElement.cs Guards [Serializable] to .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TestMethod.cs Guards [Serializable] to .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TestAssemblySettings.cs Guards [Serializable] to .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/StackTraceInformation.cs Guards [Serializable] to .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/NopTraceLogger.cs Makes MarshalByRefObject base conditional for .NET Framework remoting.
src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs Guards [Serializable] to .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/Helpers/ReflectHelper.cs Makes MarshalByRefObject/InitializeLifetimeService and System.Security usage conditional on .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.cs Makes MarshalByRefObject/InitializeLifetimeService and System.Security usage conditional on .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/Execution/TypeCache.cs Makes MarshalByRefObject/InitializeLifetimeService and System.Security usage conditional on .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestExecutionManager.cs Makes nested RemotingMessageLogger inherit MarshalByRefObject only on .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestAssemblySettingsProvider.cs Makes MarshalByRefObject/InitializeLifetimeService and System.Security usage conditional on .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumerator.cs Makes MarshalByRefObject/InitializeLifetimeService and System.Security usage conditional on .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumerationResult.cs Guards [Serializable] to .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/Deployment/TestRunDirectories.cs Guards [Serializable] to .NET Framework.
src/Adapter/MSTestAdapter.PlatformServices/Deployment/DeploymentItem.cs Guards [Serializable] on enum and class to .NET Framework.
src/Adapter/MSTest.TestAdapter/VSTestAdapter/EqtTraceLogger.cs Makes MarshalByRefObject base conditional for .NET Framework remoting.
src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MTPTraceLogger.cs Makes MarshalByRefObject base conditional for .NET Framework remoting.

Copilot's findings

  • Files reviewed: 19/19 changed files
  • Comments generated: 0

Comment thread src/TestFramework/TestFramework/Attributes/TestMethod/TestResult.cs
@Evangelink
Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented May 13, 2026

@copilot resolve the merge conflicts in this pull request

Resolved. The only conflict was in MSTestSettings.cs — the Refactor MSTestSettings into focused partial-class modules commit on main changed class MSTestSettings to partial class MSTestSettings, while this PR had added #if NETFRAMEWORK [Serializable] #endif around it. The resolution combines both: keeping partial and keeping the #if NETFRAMEWORK guard. Merge commit: 41b1475.

Removing [Serializable] for non-NETFRAMEWORK exposed an IDE0032 false positive on s_currentSettings/s_runConfigurationSettings, whose backing properties use '??=' lazy initialization (not expressible as an auto-property).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 14, 2026 18:33
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 19/19 changed files
  • Comments generated: 4

Comment thread src/Adapter/MSTestAdapter.PlatformServices/Execution/TypeCache.cs
Comment thread src/Adapter/MSTestAdapter.PlatformServices/Execution/TypeCache.cs Outdated
Comment thread src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs Outdated
Comment thread src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs Outdated
Comment thread src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs Outdated
Amaury Levé and others added 4 commits May 15, 2026 09:02
- Replace IDE0032 suppression in MSTestSettings with C# 'field' keyword pattern (matches PlatformServiceProvider/SettingsProvider style)
- Change InitializeLifetimeService overrides from 'object => null!' to 'object? => null' to match the established pattern in AssemblyResolver/AssemblyLoadWorker, removing the null-forgiving operator

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
These attributes are no-ops on modern .NET since TestMethod is no longer [Serializable] there. Wrap them in #if NETFRAMEWORK for consistency with the rest of the PR.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…#if NETFRAMEWORK

Same consistency fix as the previous commit on TestMethod: the [field: NonSerialized] attribute is a no-op on modern .NET since [Serializable] is now scoped to NETFRAMEWORK.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Update stale comment in TestResult.cs to clarify cross-AppDomain only applies on .NET Framework
- Add comment in AssemblyEnumerator.cs explaining why System.Runtime.Serialization using is unconditional

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 15, 2026 12:28
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 19/19 changed files
  • Comments generated: 0 new

@Evangelink Evangelink merged commit 1f1a647 into main May 15, 2026
18 of 21 checks passed
@Evangelink Evangelink deleted the dev/amauryleve/guard-netfx-remoting-artifacts branch May 15, 2026 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants